/*
 * This file is part of FinVis.
 *
 * FinVis is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * FinVis is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with FinVis.  If not, see <http://www.gnu.org/licenses/>
 *
 * @author Stephen Rudolph
 */

#include "FinTest.h"
#include "FinInvestment.h"
#include "FinPortfolio.h"
#include <QtTest/QtTest>

FinPortfolio scenarioPortfolio;
std::vector<InvestmentOption> investmentOptionVector;
double **covarianceArray;
FILE *interaction;

void FinTest::addInvestmentOption(char identifier, double apr, double risk)
{
    InvestmentOption option;
    option.annualPercentageReturn = apr;
    option.standardDeviation = risk;
    option.durationYears = 1;
    option.simpleInterest = false;
    option.name[0] = identifier;
    option.name[1] = '\0';
    investmentOptionVector.push_back(option);
}

void FinTest::setLiquidAssets(int value)
{
    int assets[MAX_YEARS];
    for(int i = 0; i <= MAX_YEARS; i++)
    {
        assets[i] = value;
    }

    scenarioPortfolio.setScenarioLiquidAssets(assets);
}

/**
 * Initialize an identity matrix for the covariances, unused parameter is ignored (simply there to
 * prevent QT from running this as a Unit Test.
 */
void FinTest::initializeCovarianceMatrix(int unused)
{
    double *p;
    covarianceArray = (double**) malloc(sizeof(p) * investmentOptionVector.size());
    for(unsigned int i = 0; i < investmentOptionVector.size(); i++)
        covarianceArray[i] = (double *) calloc(investmentOptionVector.size(), sizeof(double));

    for(unsigned int i = 0; i < investmentOptionVector.size(); i++)
    {
        for(unsigned int j = 0; j < investmentOptionVector.size(); j++)
        {
            if(i == j)
                covarianceArray[i][j] = 1;
            else
                covarianceArray[i][j] = 0;
        }
    }
}

unsigned int FinTest::addInvestment(char identifier, int principal)
{
    unsigned int investmentId = 0;
    bool found = false;
    for (unsigned int i = 0; i < investmentOptionVector.size(); i++)
    {
        if (investmentOptionVector[i].name[0] == identifier)
        {
            FinInvestment *investment = new FinInvestment(
                        tr(""), principal, QDate(START_YEAR, 1, 1), i);
            investmentId = scenarioPortfolio.addInvestment(investment);
            found = true;
            break;
        }
    }

    return investmentId;
}

void FinTest::initTestCase()
{
    interaction = fopen("interaction.txt", "w");
    fprintf(interaction, "Flag,Year,Principal,Type\n");
}

/**
 * This test is identical to the FinVisCalculations.pdf example.
 */
void FinTest::algorithmTestOne()
{
    this->addInvestmentOption('A', 3, 3);
    this->addInvestmentOption('B', 7, 12);
    this->setLiquidAssets(1000);
    this->initializeCovarianceMatrix(0);

    //Setup new scenario weights
    covarianceArray[0][1] = 0.5;
    covarianceArray[1][0] = 0.5;

    unsigned int aIndex = this->addInvestment('A', 400);
    unsigned int bIndex = this->addInvestment('B', 600);
    int expectedWealth = 1054;
    QVERIFY(scenarioPortfolio.expectedWealth(1) == expectedWealth);
    QVERIFY(scenarioPortfolio.optimisticWealth(1) == 1211);
    QVERIFY(scenarioPortfolio.pessimisticWealth(1) == 897);
    QVERIFY(scenarioPortfolio.optimisticWealth(1, aIndex) == expectedWealth + 61 + 96);
    QVERIFY(scenarioPortfolio.optimisticWealth(1, bIndex) == expectedWealth + 96);
    QVERIFY(scenarioPortfolio.pessimisticWealth(1, aIndex) == expectedWealth - 58 - 99);
    QVERIFY(scenarioPortfolio.pessimisticWealth(1, bIndex) == expectedWealth - 99);
}

void FinTest::cleanupTestCase()
{
    scenarioPortfolio.removeAllInvestments();
    fclose(interaction);
    free(covarianceArray);
}

QTEST_MAIN(FinTest)
